package priv.bestbeat.cloud.api.gateway.filters;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import priv.bestbeat.cloud.api.gateway.utils.ReactiveServerHttpUtil;
import priv.bestbeat.cloud.common.enums.LogPrefixEnum;
import priv.bestbeat.cloud.common.utils.JWTUtil;
import reactor.core.publisher.Mono;

/**
 * JWT 认证过滤器
 * @author 张渠钦
 * @date 2021/12/7 14:56
 */
@Slf4j
public class JWTGlobalFilter implements GlobalFilter, Ordered {

    private final static String JWT_HEADER = "authentication";

    private String[] excludePaths;

    private final AntPathMatcher antPathMatcher;

    public JWTGlobalFilter() {
        this.antPathMatcher = new AntPathMatcher();
    }

    public JWTGlobalFilter(String... excludePaths){
        this.excludePaths = excludePaths;
        this.antPathMatcher = new AntPathMatcher();
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String requestPath = exchange.getRequest().getPath().toString();

        if (!ArrayUtils.isEmpty(excludePaths)) {
            for (String excludePath : excludePaths) {
                if (this.antPathMatcher.match(excludePath,requestPath)) {
                    log.info("uri: {} request skipped JWTGlobalFilter",requestPath);
                    return chain.filter(exchange);
                }
            }
        }

        String jwt = exchange.getRequest().getHeaders().getFirst(JWT_HEADER);
        if (StringUtils.isBlank(jwt)) {
            exchange.getResponse().setStatusCode(HttpStatus.BAD_REQUEST);
            log.error("{} uri: {} request header that name called {}", LogPrefixEnum.CREDENTIAL_REQUIRED,requestPath,JWT_HEADER);
            return ReactiveServerHttpUtil.sendMono(exchange.getResponse(),String.format("%s header value not found",JWT_HEADER));
        }
        if (!JWTUtil.basicValid(jwt)) {
            log.error("{} uri: {} request header value that name called {}",LogPrefixEnum.CREDENTIAL_INVALID,requestPath,JWT_HEADER);
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return ReactiveServerHttpUtil.sendMono(exchange.getResponse(),String.format("%s header value is invalid",JWT_HEADER));
        }
        log.info("{} uri: {} request with JWT {}",LogPrefixEnum.CREDENTIAL_AUTHORIZED,requestPath,jwt);

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 10;
    }

}
